import datetime
import sys
import arrow
from flask_script import Manager

from app.scripts.alert_group_rollback import AlertGroupRollback
from app.scripts.asset_change_task_addition import AssetChangeTaskAddition
from app.scripts.close_alert_group import CloseAlertGroup
from app.scripts.export_user_tasks import UserTasks
from app.scripts.refresh_alert_group_info import RefreshAlertGroupInfo
from app.scripts.job_ipv6_support_status import JobIpv6SupportStatus
from app.scripts.job_security_status import JobSecurityStatus
from app.scripts.other_asset_task_status import OtherAssetTaskStatus
from app.scripts.reuse_property_config import UserConfigReuse
from app.scripts.open_monitor_alert_script import OpenMonitorOrAlert
from app.scripts.asset_task_rewrite import RewriteAssetTask
from app.scripts.ui_opt_rollback import UiOptRollback
from app.scripts.change_ipv6_task_type import ChangeTaskGroupType
from run import app
from app.config.settings import MONGODB_SETTINGS
from app.scripts.fix_ipv6_score import FixIPv6Score

manager = Manager(app)


@manager.option("-a", "--action", dest="action", help="操作类型:monitor, alert", required=True,
                choices=('monitor', 'alert'))
@manager.option("-s", "--switch", dest="switch", help="开关: open, close", required=True, choices=('open', 'close'))
@manager.option("-us", "--usernames", dest="usernames", help="用户名", required=True)
@manager.option("-js", "--jobs", dest="jobs", help="资产地址", required=False)
def open_monitor_or_alert(action, usernames, jobs, switch='open'):
    """
    python manage.py open_monitor_or_alert -a monitor -s open -us fan7-20@qq.com
    python manage.py open_monitor_or_alert -a monitor -s close -us fan7-20@qq.com -js https://test.com,https://test1.com

    python manage.py open_monitor_or_alert -a alert -s open -us fan7-20@qq.com
    python manage.py open_monitor_or_alert -a alert -s close -us fan7-20@qq.com -js https://test.com,https://test1.com
    """
    task_handler = OpenMonitorOrAlert()
    if switch == 'open' or switch is None:
        switch = True
    else:
        switch = False

    enable_alert = switch
    enable_monitor = switch

    status, result = task_handler.execute(action, usernames, jobs, enable_alert, enable_monitor)
    if status:
        if not result:
            msg = f"执行成功的资产地址： [], 原因: 合法资产已经在目标状态"
        else:
            msg = f"执行成功的资产地址：{result}"
    else:
        msg = f"执行成功的资产地址： [], 原因: {result}"
    print(msg)


@manager.option("-0", "--output", dest="output_path", default=None, help="导出路径，path/*.csv")
@manager.option("-t", "--type", dest="task_type", default="vul", help="导出类型", choices=('vul',))
@manager.option("-u", "--username", dest="username", help="用户名", required=True)
def export_task(username, task_type, output_path):
    """
    python manage.py export_task -u xxx@xxx.com
    """
    task_handler = UserTasks(username=username, task_type=task_type)
    file_path = task_handler.export(to_path=output_path)
    print(f"导出csv成功：{file_path}")


@manager.option("-a", "--api", dest="graphql_api", default="https://www.scanv.com/graphql", help="graphql api 地址")
@manager.option("-i", "--interval", dest="interval", default=30, help="下发任务间隔, 默认30(s)")
@manager.option("-t", "--targets", dest="targets", help="目标资产地址")
@manager.option("-o", "--origin", dest="origin", help="已存在的模板资产地址", required=True)
@manager.option("-u", "--username", dest="username", help="用户名", required=True)
def batch_config(username, origin, targets, graphql_api, interval):
    if MONGODB_SETTINGS[0].get("db", "").startswith(
            "cloudmonitor-dev") and graphql_api == "https://www.scanv.com/graphql":
        print("error: 地址错误，请指定地址'-a'参数为开发环境地址")
        sys.exit()
    targets = targets.split(",") if targets else []
    handler = UserConfigReuse(
        username=username,
        template_url=origin,
        targets=targets,
        interval=int(interval),
        graphql_api=graphql_api
    )
    handler.post_to_graph()


@manager.option("-u", "--username", dest="username", help="用户名", required=False)
def refresh_alert_group_info(username):
    RefreshAlertGroupInfo().service()


@manager.option("-u", "--username", dest="username", help="用户名", required=False)
def alert_group_rollback(username):
    AlertGroupRollback().service()


@manager.option("-t", "--task", dest="task_id", default="", help="tasks表ID,会同步大于给定ID的任务,不填则自动同步所有任务")
@manager.option("-j", "--jobs", dest="job_ids", default="", help="jobs表ID,多个ID以逗号分割,指定同步资产任务,不填则自动同步所有任务")
def rewrite_asset_task(task_id, job_ids):
    """
    同步tasks数据到asset_tasks
    python manage.py rewrite_asset_task   # 同步所有任务
    python manage.py rewrite_asset_task  -t '632d7776dbec40c6aa7dba5a' # 同步id大于632d7776dbec40c6aa7dba5a的任务
    python manage.py rewrite_asset_task  -j '632d7776dbec40c6aa7dba6a,632d7776dbec40c6aa7dba6b' # 同步指定job的任务
    """
    job_id_list = job_ids.split(",") if job_ids else []
    handler = RewriteAssetTask(
        job_ids=job_id_list,
        last_task_id=task_id,
    )
    handler.run()


@manager.option("-u", "--username", dest="username", help="用户名", required=False)
def job_security_status(username):
    JobSecurityStatus().service()


@manager.option("-u", "--username", dest="username", help="用户名", required=False)
def job_ipv6_support_status(username):
    JobIpv6SupportStatus().service()


@manager.option("-u", "--username", dest="username", help="用户名", required=False)
def fix_ipv6_score(username):
    FixIPv6Score().service()


@manager.option("-u", "--username", dest="username", help="用户名", required=False)
def asset_change_task_addition(username):
    AssetChangeTaskAddition().service()


@manager.option("-t", "--task_group_type", dest="task_group_type", help="任务分组类型", required=False, default="")
def other_asset_task_status(task_group_type):
    OtherAssetTaskStatus().service(task_group_type)


@manager.option("-u", "--username", dest="username", help="用户名", required=False)
def ui_opt_rollback(username):
    UiOptRollback().service()


@manager.option("-o", "--ori_type", dest="ori_type", help="原始类型", default="web")
@manager.option("-t", "--to_type", dest="to_type", help="修改后的类型", default="ipv6")
def change_type_group_type(ori_type, to_type):
    ChangeTaskGroupType(ori_type=ori_type, to_type=to_type).run()


@manager.option("-us", "--usernames", dest="usernames", help="修改后的类型", default="")
def close_alert_group(usernames: str):
    username_list = usernames.split(",")
    CloseAlertGroup().service(username_list)


@manager.option("-r", "--run", help="处理数据", default=False, action='store_true')
def update_uneable_task(run=False):
    """
    python manage.py update_uneable_task 不处理数据，输出将处理数据统计信息
    python manage.py update_uneable_task --run 处理数据
    """
    from app.scripts.update_unenable_task_type import UpdateUnenableTask
    if run:
        UpdateUnenableTask().run()
    else:
        UpdateUnenableTask()


@manager.option("-r", "--run", help="处理数据", default=False, action='store_true')
def update_packages(run=False):
    """
    python manage.py update_packages 不处理数据，输出将处理数据统计信息
    python manage.py update_packages --run 处理数据
    """
    from app.scripts.update_packages import UpdatePackages
    if run:
        UpdatePackages().run()
    else:
        UpdatePackages()


@manager.option("-r", "--run", help="处理数据", default=False, action='store_true')
def available_node(run=False):
    """
    python manage.py available_node 不处理数据，输出将处理数据统计信息
    python manage.py available_node --run 处理数据
    """
    from app.scripts.available_node import AvailableNode
    nodes = [
        ("nanchang2-cuc1", "shijiazhuang-cmc1"),
        ("xian2-ctc1", "fuzhou-ctc1"),
    ]
    available_task_ids, ws_task_ids = set(), set()
    for node in nodes:
        old, new = node
        if run:
            available_task_ids.update(AvailableNode(old, new).run())
        else:
            AvailableNode(old, new).log()
        ws_task_ids.update(set(AvailableNode(old, new).ws_task_log()))
    if available_task_ids:
        AvailableNode.enable_tasks(list(available_task_ids))
    if ws_task_ids and run:
        AvailableNode.ws_task_run(list(ws_task_ids))


@manager.command
def output():
    from app.output.main import main
    main()


@manager.option("-s", "--start_time", default="", help="报告周期开始时间, 如果不传此参数, 默认为7天前")
@manager.option("-e", "--end_time", default="", help="报告周期结束时间, 如果不传此参数, 默认为当前时间")
@manager.option("-u", "--username", default="", required=True, help="指定推送报告用户, 多个用户使用','分割, 特别的如果传入 'all' 给所有人推送")
@manager.option("-P", "--phone", default="", help="指定接收报告的手机号, 如果不传此参数, 默认给用户默认告警联系人, 多个使用','分割, "
                                                  "手机号、邮箱、微信三个参数任意给出一个就不会给默认告警联系人推送报告")
@manager.option("-E", "--email", default="", help="指定接收报告的邮箱, 如果不传此参数, 默认给用户默认告警联系人, 多个使用','分割")
@manager.option("-W", "--wechat", default="", help="指定接收报告的微信ID, 如果不传此参数, 默认给用户默认告警联系人, 多个使用','分割")
def push_report(start_time, end_time, username, phone, email, wechat):
    from app.report_push.main import report_push
    from dateutil.parser import parse as dtparse
    keywords = {}
    if not username:
        print("必须指定推送用户，特别的如果传入 'all' 给所有人推送")
        exit(-1)
    if username != "all":
        keywords.update({"usernames": username.split(",")})
    if start_time:
        try:
            keywords.update({"start_time": arrow.get(dtparse(f"{start_time} CST")).to("utc").datetime})
        except:
            raise ValueError(f"start_time: {start_time} error")
    if end_time:
        try:
            keywords.update({"end_time": arrow.get(dtparse(f"{end_time} CST")).to("utc").datetime})
        except:
            raise ValueError(f"end_time: {end_time} error")
    if phone:
        keywords.update({"phone": [_ for _ in phone.split(",") if _]})
    if email:
        keywords.update({"email": [_ for _ in email.split(",") if _]})
    if wechat:
        keywords.update({"wechat": [_ for _ in wechat.split(",") if _]})
    if any([phone, email, wechat]):
        keywords.update({"default_receiver": False})
    report_push(**keywords)


@manager.option("-p", "--path", default="", help="导出忽略威胁保存csv路径")
@manager.option("-u", "--username", default="", required=True, help="用户名")
def export_ignore_warnings(path="", username=""):
    from app.scripts.export_ignore_warnings import export_ignore_warnings
    if path and not path.endswith("csv"):
        print("只支持存在存储csv格式文件")
        exit(-1)
    export_ignore_warnings(username=username, path=path)


@manager.option("-u", "--updated_at", dest="updated_at", required=True,
                help="推送配置更新时间, 只会修改更新小于此值的配置, 防止重复更新")
def update_push_config(updated_at):
    """
    更新已经开启了任务结果推送用户配置，增加默认推送任务类型， 不包括篡改监测， 防止引起用户系统错误
    python manage.py update_push_config
    """
    from app.scripts.api_push_task_types import update_push_config as _update_push_config
    _update_push_config(updated_at)


@manager.option("-p", "--pkg_ids", dest="pkg_ids",
                help="需要更新的套餐ID, 多个以','分割, 不传默认则更新支持web漏洞监测的套餐")
def update_pkg_with_change(pkg_ids=""):
    """
    更新套餐数据，给支持web漏洞监测的套餐增加篡改监测功能
    python manage.py update_pkg_with_change
    python manage.py update_pkg_with_change --pkg_ids "6639c46b98574e0aeb22e3ca,6639c46b98574e0aeb22e3cb"
    """
    from app.scripts.change_check_pkg import update_pkg_data
    if pkg_ids:
        update_pkg_data(pkg_ids=pkg_ids.split(","))
    else:
        update_pkg_data()


@manager.option("-p", "--pkg_ids", dest="pkg_ids",
                help="套餐ID,给购买了指定套餐的用户开通篡改监测功能, 多个以','分割")
@manager.option("-u", "--user_ids", dest="user_ids",
                help="用户ID, 给指定用户开通篡改监测功能, 多个以','分割")
def update_user_with_change(pkg_ids="", user_ids=""):
    """
    给付费用户开通篡改监测功能， 如果pkg_ids，user_ids都为空，则默认给所有购买了web漏洞监测
    功能且未过期的用户开通, 执行此命令前先执行 python manage.py update_pkg_with_change , 否则无效
    python manage.py update_user_with_change
    python manage.py update_user_with_change --user_ids "6639c46b98574e0aeb22e3ca,6639c46b98574e0aeb22e3cb"
    """
    from app.scripts.change_check_pkg import update_user_data
    kwargs = {}
    if pkg_ids:
        kwargs.update({"pkg_ids": pkg_ids.split(",")})
    if user_ids:
        kwargs.update({"user_ids": user_ids.split(",")})
    update_user_data(**kwargs)


@manager.option("--task_types", "--task_types", dest="task_types",
                help="需要同步的监测项， 多个以逗号分割")
@manager.option("--username", "--username", dest="username",
                help="用户名")
@manager.option("--uid", "--uid", dest="uid",
                help="用户ID")
@manager.option("--job_id", "--job_id", dest="job_id",
                help="模版资产ID")
@manager.option("--target_url", "--target_url", dest="target_url",
                help="模版资产地址，在没有job_id是生效")
@manager.option("--source_ip", "--source_ip", dest="source_ip",
                help="模版资产IP, 和target_url共同生效")
@manager.option("--is_all", "--is_all", dest="is_all", default=False,
                help="是否同步给所有资产")
@manager.option("--targets", "--targets", dest="targets",
                help="is_all为false时生效， 每个资产由 资产地址|源站IP 组成， 多个资产以逗号分割")
def copy_sec_task_settings(
    task_types=None,
    username=None,
    uid=None,
    job_id=None,
    target_url=None,
    source_ip=None,
    is_all=False,
    targets=None
):
    """
    批量同步web安全监测任务配置
    eg:
    python manage.py copy_sec_task_settings --username='safe@sou.edu.cn' --target_url='https://jrxy.ai-study.net' --source_ip='null' --is_all=true
    """
    from app.scripts.batch_update_settings import update_task_settings
    update_task_settings(
        task_types=task_types,
        username=username,
        uid=uid,
        job_id=job_id,
        target_url=target_url,
        source_ip=source_ip,
        is_all=is_all,
        targets=targets
    )


if __name__ == '__main__':
    manager.run()
